package com.smart.agent.mqtt;

import com.smart.agent.bean.mqtt.MqttBean;
import com.smart.agent.bean.remote.RemoteBean;
import com.smart.agent.remote.Remote;
import com.smart.agent.remote.RemoteFactory;
import com.smart.agent.tools.http.HttpHelper;
import com.smart.agent.tools.http.Params;
import com.smart.agent.tools.http.PostType;
import com.smart.agent.tools.http.Response;
import com.smart.agent.tools.json.JsonHelper;
import com.smart.agent.tools.mqtt.MqttHelper;
import com.smart.agent.tools.mqtt.QOS;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class MqttInit implements ApplicationRunner, AutoCloseable {
    private static final Logger logger = LoggerFactory.getLogger(MqttInit.class);

    @Value("${smart.server.host}")
    private String smartServerHost;
    @Value("${smart.server.port}")
    private String smartServerPort;

    @Value("${smart.agent.key}")
    private String agentKey;

    @Value("${mqtt.qos}")
    private QOS qos;
    private static String url; // mqtt 服务器的地址
    private static String baseTopic; // topic base 地址，例如：SMART/SUB/29002272-4659-4808-a804-08ce3388b136 这个 SMART 就是 topicBase
    private static String subTopic; // 订阅 的 topic 地址，例如：SMART/SUB/29002272-4659-4808-a804-08ce3388b136 这个是下发命令的 topic，agent.key=29002272-4659-4808-a804-08ce3388b136 的 agent
    private static String pubTopic; // 发布 的 topic 地址，例如：SMART/PUB/29002272-4659-4808-a804-08ce3388b136，这个是发布（上报）的 topic，agent.key=29002272-4659-4808-a804-08ce3388b136 的 agent
    private static MqttHelper subMqttHelper = new MqttHelper(); // 订阅，接收命令的通道
    private static MqttHelper pubMqttHelper = new MqttHelper(); // 发布，上报结果的通道

    @Override
    public void run(ApplicationArguments args) throws Exception {
        HttpHelper.setMediaType(PostType.JSON);
        Params bodyParams = new Params();
        bodyParams.add("key", agentKey);
        Response response = HttpHelper.getInstance().post("http://" + smartServerHost + ":" + smartServerPort + "/api/controller/agents/online", bodyParams);

        JsonHelper jsonHelper = (JsonHelper)response.getBody();
        MqttBean mqtt = jsonHelper.getBean(MqttBean.class, "$.data");
        url = mqtt.getUrl();
        baseTopic = mqtt.getBaseTopic();
        subTopic = baseTopic + "/SUB/" + agentKey;
        pubTopic = baseTopic + "/PUB/" + agentKey;

        connectMqtt(); // 创建 mqtt 通道并监听处理远程控制命令
        logger.info("创建 MQTT 通道， url: {}, baseTopic: {}, subTopic: {}, pubTopic: {}", url, baseTopic, subTopic, pubTopic);
    }

    /**
     * 创建 mqtt 通道并监听处理远程控制命令
     * @throws MqttException
     */
    public void connectMqtt() throws MqttException {
        // 接收远程控制
        subMqttHelper = new MqttHelper();
        subMqttHelper.setQos(qos);
        subMqttHelper.getInstance(url, "SUB:"+agentKey);

        // 上报远程控制执行的结果
        pubMqttHelper = new MqttHelper();
        pubMqttHelper.setQos(qos);
        pubMqttHelper.getInstance(url, "PUB:"+agentKey);

        subMqttHelper.subscribe(new MqttHelper.MqttListener() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
            }

            @Override
            public void connectionLost(Throwable cause) {
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                logger.debug("收到 MQTT 消息，topic:{}, message:{}", topic, message);

                if (topic.equals(subTopic)) {
                    try {
                        if (JsonHelper.isJson(message.toString())) {
                            // 创建 Remote 并执行对应的远程控制
                            Remote remote = RemoteFactory.create(message.toString());
                            remote.execute();

                            pubMqttHelper.publish(pubTopic, remote.getRemoteBean().toString()); // 通过 mqtt 上报执行结果
                        } else {
                            throw new IllegalArgumentException("远程调用数据不合法：非 JSON 格式字符串。message: " + message.toString());
                        }
                    } catch (IllegalArgumentException e) {
                        logger.error(e.getMessage());

                        RemoteBean remoteBean = new RemoteBean();
                        remoteBean.setCmd("");
                        remoteBean.setResultFail(e.getMessage());
                        pubMqttHelper.publish(pubTopic, remoteBean.toString()); // 通过 mqtt 上报执行结果
                    }
                } else {
                    logger.info("未识别的 topic。topic：" + topic + ", message: " + message);
                }
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
            }
        }, subTopic);


        // 测试代码
        try {
            pubMqttHelper.publish("SMART/SUB/29002272-4659-4808-a804-08ce3388b136", "{\"agentKey\":\"123\", \"udId\":\"1111\", \"cmd\":\"RemoteCall\", \"data\":{\"class_name\":\"ddd\"}}");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * close 方法，释放资源
     * @throws MqttException
     */
    public void close() throws MqttException {
        logger.info("断开 MQTT 通道");
        pubMqttHelper.close(); // 关闭 上报远程控制执行的结果的 mqtt 连接
        subMqttHelper.close(); // 关闭 接收远程控制的 mqtt 连接
    }
}
